package de.zigapeda.flowspring.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collections;

import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.border.Border;

import sun.swing.DefaultLookup;
import de.zigapeda.flowspring.Main;
import de.zigapeda.flowspring.data.PlaylistTrack;
import de.zigapeda.flowspring.data.Title;
import de.zigapeda.flowspring.gui.dnd.PlaylistTransferHandler;

public class Playlist extends JPanel implements ListCellRenderer<PlaylistTrack>, MouseListener, KeyListener {
	private static final long	serialVersionUID	= -3606283321945550386L;
	
	private DefaultListModel<PlaylistTrack> playlistmodel;
	private PlaylistTrack track;
	private JList<PlaylistTrack> playlist;
	private PlaylistControlls playlistcontrolls;
	
	public Playlist() {
		super();
		this.track = null;
	    this.playlistmodel = new DefaultListModel<>();
	    this.playlist = new JList<>();
	    this.playlist.addKeyListener(this);
	    this.playlist.setModel(this.playlistmodel);
		this.playlist.setDragEnabled(true);
		this.playlist.setDropMode(DropMode.INSERT);
		this.playlist.setTransferHandler(new PlaylistTransferHandler(this.playlist));
		this.playlist.setCellRenderer(this);
		this.playlist.addMouseListener(this);
		this.setLayout(new BorderLayout());
		this.add(new JScrollPane(this.playlist));
		this.playlistcontrolls = new PlaylistControlls(this);
		this.add(this.playlistcontrolls,BorderLayout.PAGE_END);
	}

	public PlaylistTrack getCurrent() {
		if(this.track == null) {
			this.track = this.getNext(false);
		}
		this.count();
		return this.track;
	}

	public PlaylistTrack getPrevious() {
		if(this.track == null) {
			if(this.playlistmodel.getSize() > 0) {
				this.track = this.playlistmodel.lastElement();
			} else {
				this.track = null;
			}
		} else {
			if(this.playlistmodel.indexOf(this.track) - 1 >= 0){
				this.track = this.playlistmodel.getElementAt(this.playlistmodel.indexOf(this.track) - 1);
			} else {
				this.track = null;
			}
		}
		this.repaint();
		this.count();
		return this.track;
	}

	public PlaylistTrack getNext(boolean careOnRepeat) {
		if(this.track == null) {
			if(this.playlistmodel.getSize() > 0) {
				this.track = this.playlistmodel.firstElement();
			} else {
				this.track = null;
			}
		} else {
			if(this.playlistcontrolls.getRepeat() != PlaylistControlls.REPEAT_ONE) {
				if(this.playlistmodel.getSize() > this.playlistmodel.indexOf(this.track) + 1){
					this.track = this.playlistmodel.getElementAt(this.playlistmodel.indexOf(this.track) + 1);
				} else {
					if(this.playlistcontrolls.getRepeat() == PlaylistControlls.REPEAT_ALL || careOnRepeat == false) {
						this.track = this.playlistmodel.firstElement();
					} else {
						this.track = null;
					}
				}
			} else {
				if(careOnRepeat == false) { //next button clicked
					if(this.playlistmodel.getSize() > this.playlistmodel.indexOf(this.track) + 1){
						this.track = this.playlistmodel.getElementAt(this.playlistmodel.indexOf(this.track) + 1);
					} else {
						this.track = this.playlistmodel.firstElement();
					}
				}
			}
		}
		this.repaint();
		this.count();
		return this.track;
	}
	
	private void count() {
		if(this.track != null) {
			if(this.track.getId() != null) {
				Title.addCount(this.track.getId());
			}
		}
	}

	public void addTrack(PlaylistTrack playlisttrack) {
		this.playlistmodel.addElement(playlisttrack);
		if(Main.getWindow().getPlayercontroller().isStopped()) {
			this.track = playlisttrack;
			Main.getWindow().getPlayercontroller().play();
		}
	}

	public Component getListCellRendererComponent(JList<? extends PlaylistTrack> list, PlaylistTrack value, int index, boolean isSelected, boolean cellHasFocus) {
        JLabel label;
		if(value == this.track) {
			label = new JLabel("► " + value.toString());
		} else {
			label = new JLabel(value.toString());
		}
        if (cellHasFocus == true || value == this.track) {
        	Border border = null;
            if (isSelected == true) {
                border = DefaultLookup.getBorder(this, ui, "List.focusSelectedCellHighlightBorder");
            }
            if (border == null) {
                border = DefaultLookup.getBorder(this, ui, "List.focusCellHighlightBorder");
            }
            label.setBorder(border);
        }
		if(isSelected == true) {
			label.setOpaque(true);
			label.setBackground(this.playlist.getSelectionBackground());
			label.setForeground(this.playlist.getSelectionForeground());
		}
        return label;
	}

	public void mouseClicked(MouseEvent e) {
		if(e.getClickCount() == 2) {
			if(this.playlist.getSelectedIndex() != -1) {
				if(this.track != this.playlist.getSelectedValue()) {
					Main.getWindow().getPlayercontroller().stop();
					this.track = this.playlist.getSelectedValue();
					Main.getWindow().getPlayercontroller().play();
					this.repaint();
				}
			}
		}
	}

	public void mousePressed(MouseEvent e) {
		
	}

	public void mouseReleased(MouseEvent e) {
		
	}

	public void mouseEntered(MouseEvent e) {
		
	}

	public void mouseExited(MouseEvent e) {
		
	}

	public void keyTyped(KeyEvent e) {
		
	}

	public void keyPressed(KeyEvent e) {
		
	}

	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode() == KeyEvent.VK_DELETE) {
			if(this.playlist.getSelectedIndex() != -1) {
				if(this.playlist.getSelectedValue() == this.track) {
					Main.getWindow().getPlayercontroller().stop();
				}
				int sel = this.playlist.getSelectedIndex();
				this.playlistmodel.remove(this.playlist.getSelectedIndex());
				if(this.playlistmodel.getSize() != 0) {
					if(this.playlistmodel.getSize() > sel) {
						this.playlist.setSelectedIndex(sel);
					} else {
						this.playlist.setSelectedIndex(sel - 1);
					}
				}
			}
		} else if(e.getKeyCode() == KeyEvent.VK_ENTER) {
			if(this.playlist.getSelectedIndex() != -1) {
				if(this.track != this.playlist.getSelectedValue()) {
					Main.getWindow().getPlayercontroller().stop();
					this.track = this.playlist.getSelectedValue();
					Main.getWindow().getPlayercontroller().play();
					this.repaint();
				}
			}
		}
	}

	public void shuffle() {
		this.playlistmodel.removeElement(this.track);
		ArrayList<PlaylistTrack> list = new ArrayList<>();
		for(int i = 0; i < this.playlistmodel.getSize(); i++) {
			list.add(this.playlistmodel.get(i));
		}
		Collections.shuffle(list);
		this.playlistmodel.clear();
		for(int i = 0; i < list.size(); i++) {
			this.playlistmodel.addElement(list.get(i));
		}
		this.playlistmodel.add(0, this.track);
	}
	
//	static class ListMoveDataFlavor extends DataFlavor {
//		
//		private final DefaultListModel<PlaylistTrack> model;
//		
//		public ListMoveDataFlavor(DefaultListModel<PlaylistTrack> model) {
//			super(ListMoveTransferData.class, "List Data");
//			this.model = model;
//		}
//		
//		public DefaultListModel<PlaylistTrack> getModel() {
//			return model;
//		}
//		
//		public int hashCode() {
//			final int prime = 31;
//			int result = super.hashCode();
//			result = prime * result + ((model == null) ? 0 : model.hashCode());
//			return result;
//		}
//		
//		public boolean equals(DataFlavor that) {
//			if (this == that) {
//				return true;
//			}
//			if (!super.equals(that) || getClass() != that.getClass()) {
//				return false;
//			}
//			return match(model, that);
//		}
//
//		public static boolean match(DefaultListModel<PlaylistTrack> model, DataFlavor flavor) {
//			return flavor instanceof ListMoveDataFlavor
//					&& ((ListMoveDataFlavor) flavor).getModel() == model;
//		}
//	}
//	
//	private static class ListMoveTransferData {
//		
//		private final DefaultListModel<PlaylistTrack> model;
//		private final int[] indices;
//		
//		ListMoveTransferData(DefaultListModel<PlaylistTrack> model, int[] indices) {
//			this.model = model;
//			this.indices = indices;
//		}
//		
//		int[] getIndices() {
//			return indices;
//		}
//		
//		public DefaultListModel<PlaylistTrack> getModel() {
//			return model;
//		}
//	}
//	
//	static class ListMoveTransferable implements Transferable {
//		
//		private final ListMoveTransferData	data;
//		
//		public ListMoveTransferable(ListMoveTransferData data) {
//			this.data = data;
//		}
//		
//		public DataFlavor[] getTransferDataFlavors() {
//			return new DataFlavor[] { new ListMoveDataFlavor(data.getModel()) };
//		}
//		
//		public boolean isDataFlavorSupported(DataFlavor flavor) {
//			return ListMoveDataFlavor.match(data.getModel(), flavor);
//		}
//		
//		public Object getTransferData(DataFlavor flavor)
//				throws UnsupportedFlavorException, IOException {
//			if (!isDataFlavorSupported(flavor)) {
//				throw new UnsupportedFlavorException(flavor);
//			}
//			return data;
//		}
//	}
//	
//	static class ListMoveTransferHandler extends TransferHandler {
//		private static final long	serialVersionUID	= 6703461043403098490L;
//		
//		@SuppressWarnings("unchecked")
//		public int getSourceActions(JComponent c) {
//			final JList<PlaylistTrack> list = (JList<PlaylistTrack>) c;
//			return list.getModel() instanceof DefaultListModel ? MOVE : NONE;
//		}
//		
//		@SuppressWarnings("unchecked")
//		public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
//			if (!(comp instanceof JList)
//					|| !(((JList<PlaylistTrack>) comp).getModel() instanceof DefaultListModel)) {
//				return false;
//			}
//			
//			final DefaultListModel<PlaylistTrack> model = (DefaultListModel<PlaylistTrack>) ((JList<PlaylistTrack>) comp)
//					.getModel();
//			for (DataFlavor f : transferFlavors) {
//				if (ListMoveDataFlavor.match(model, f)) {
//					return true;
//				}
//			}
//			return false;
//		}
//		
//		@SuppressWarnings("unchecked")
//		protected Transferable createTransferable(JComponent c) {
//			final JList<PlaylistTrack> list = (JList<PlaylistTrack>) c;
//			final int[] selectedIndices = list.getSelectedIndices();
//			return new ListMoveTransferable(new ListMoveTransferData(
//					(DefaultListModel<PlaylistTrack>) list.getModel(), selectedIndices));
//		}
//		
//		@SuppressWarnings("unchecked")
//		public boolean importData(TransferHandler.TransferSupport info) {
//			final Component comp = info.getComponent();
//			if (!info.isDrop() || !(comp instanceof JList)) {
//				return false;
//			}
//			final JList<PlaylistTrack> list = (JList<PlaylistTrack>) comp;
//			final ListModel<PlaylistTrack> lm = list.getModel();
//			if (!(lm instanceof DefaultListModel)) {
//				return false;
//			}
//			
//			final DefaultListModel<PlaylistTrack> listModel = (DefaultListModel<PlaylistTrack>) lm;
//			final DataFlavor flavor = new ListMoveDataFlavor(listModel);
//			if (!info.isDataFlavorSupported(flavor)) {
//				return false;
//			}
//			
//			final Transferable transferable = info.getTransferable();
//			try {
//				final ListMoveTransferData data = (ListMoveTransferData) transferable
//						.getTransferData(flavor);
//				
//				// get the initial insertion index
//				final JList.DropLocation dropLocation = list.getDropLocation();
//				int insertAt = dropLocation.getIndex();
//
//				// get the indices sorted (we use them in reverse order, below)
//				final int[] indices = data.getIndices();
//				Arrays.sort(indices);
//				
//				// remove old elements from model, store them on stack
//				final Stack<PlaylistTrack> elements = new Stack<PlaylistTrack>();
//				int shift = 0;
//				for (int i = indices.length - 1; i >= 0; i--) {
//					final int index = indices[i];
//					if (index < insertAt) {
//						shift--;
//					}
//					elements.push(listModel.remove(index));
//				}
//				insertAt += shift;
//				
//				// insert stored elements from stack to model
//				final ListSelectionModel sm = list.getSelectionModel();
//				try {
//					sm.setValueIsAdjusting(true);
//					sm.clearSelection();
//					final int anchor = insertAt;
//					while (!elements.isEmpty()) {
//						listModel.insertElementAt(elements.pop(), insertAt);
//						sm.addSelectionInterval(insertAt, insertAt++);
//					}
//					final int lead = insertAt - 1;
//					if (!sm.isSelectionEmpty()) {
//						sm.setAnchorSelectionIndex(anchor);
//						sm.setLeadSelectionIndex(lead);
//					}
//				} finally {
//					sm.setValueIsAdjusting(false);
//				}
//				return true;
//			} catch (UnsupportedFlavorException ex) {
//				return false;
//			} catch (IOException ex) {
//				return false;
//			}
//		}
//	}
}